/** @file    FormConsole.cpp
 *  @author  Alessandro Polo
 *  @version $Id: FormConsole.cpp 2883 2010-08-09 14:51:56Z alex $
 *  @brief
 * File containing methods for the wosh::gui::FormConsole class.
 * The header for this class can be found in FormConsole.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include "FormConsole.h"
 #include "ui_FormConsole.h"

 #include <core/ObjectAllocator.h>
 #include <core/SessionManager.h>
 #include <core/WoshKernel.h>

 #include <framework/gui/GuiUtilities.h>
 #include <QFontDialog>
 #include <QColorDialog>
 #include <QMessageBox>


using namespace std;
namespace wosh {
 namespace gui {

 WOSH_REGISTER(wosh::gui::FormConsole, "wosh::gui::IWidgetGeneric", 1.0, _static_FormConsole )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

FormConsole::FormConsole(QWidget *parent)
	: IWidgetGeneric(parent) {
	this->m_ui = new Ui::FormConsole();
	this->m_ui->setupUi(this);

	this->scrollAuto = true;
	this->m_ui->chkScrollAuto->setChecked(this->scrollAuto);

	this->sessionDebug = false;
	this->m_ui->cmbSessionDebug->setCurrentIndex(this->sessionDebug);

	this->m_ui->cmbWordWrap->setCurrentIndex(0);

	connect(this->m_ui->txtInput, SIGNAL(returnPressed()), this, SLOT(shellSend()));

	connect(this->m_ui->txtCurrentBus, SIGNAL(editingFinished()), this, SLOT(txtCurrentBus_editingFinished()));
	connect(this->m_ui->txtCurrentKernel, SIGNAL(editingFinished()), this, SLOT(txtCurrentKernel_editingFinished()));

	connect(this->m_ui->cmbSessionDebug, SIGNAL(activated(int)), this, SLOT(cmbSessionDebug_activated(int)));
	
	connect(this->m_ui->cmbWordWrap, SIGNAL(activated(int)), this, SLOT(cmbWordWrap_activated(int)));
	connect(this->m_ui->chkScrollAuto, SIGNAL(clicked()), this, SLOT(chkScrollAuto_clicked()));

	connect(this->m_ui->btnFontColorChange, SIGNAL(clicked()), this, SLOT(btnFontColorChange_clicked()));
	connect(this->m_ui->btnFontChange, SIGNAL(clicked()), this, SLOT(btnFontChange_clicked()));
	connect(this->m_ui->btnBackgroundChange, SIGNAL(clicked()), this, SLOT(btnBackgroundChange_clicked()));

	connect(this, SIGNAL(onPrintMessage(const QString&)), this, SLOT(e_onPrintMessage(const QString&)), Qt::QueuedConnection);
	connect(this, SIGNAL(onBusChanged()), this, SLOT(e_onBusChanged()), Qt::QueuedConnection);
	connect(this, SIGNAL(onLocationChanged()), this, SLOT(e_onLocationChanged()), Qt::QueuedConnection);

	this->session = new SessionProxy();
	this->session->setListener(this);
	session->setCreatorURI( getWidgetURI() );

	this->setWindowTitle( tr("Terminal") + " - " + this->session->getURI().getName().c_str() );
	this->getWidgetURI().setName("FormConsole#" + this->session->getURI().getName() );
	this->setTargetURI(this->session->getURI());

	WRESULT registered = WoshKernel::getInstance()->sessions().registerSession(this->session);
	if ( WFAILED(registered) ) {
		QMessageBox::critical(this, this->windowTitle(), QString("FAILED Registering Session!") );
		this->session->setListener(NULL);
		delete this->session; this->session = NULL;
				
		return;
	 }

	this->m_ui->txtInput->setFocus();
 }

FormConsole::~FormConsole() {
	WRESULT unregistered = WoshKernel::getInstance()->sessions().unRegisterSession( this->session );
	if ( WFAILED(unregistered) ) {
		QMessageBox::critical(this, this->windowTitle(), QString("FAILED UnRegistering Session!") );
	 }
	else {
		delete this->session; this->session = NULL;
	 }
	delete this->m_ui;
 }

void FormConsole::changeEvent(QEvent *e) {
	QWidget::changeEvent(e);
	if ( e->type() == QEvent::LanguageChange )
		this->m_ui->retranslateUi(this);
 }

void FormConsole::closeEvent(QCloseEvent*) {
	this->deleteLater();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// SESSION EVENTS

void FormConsole::session_registration( short reg_unreg, wosh::communication::SessionProxy* session ) {
	if ( session == NULL ) return;
	if ( reg_unreg == 1 ) { // registered
		this->session->setWelcomePrompted(false);
		this->session->setUsernameLogged( GuiSession::getInstance().getUsername() );
		this->session->setCredentials( GuiSession::getInstance().getCredentials() );
		this->session->setRestrictions( Session::ALLOW_ALL );
		this->session->login();
		this->session->open();

		this->m_ui->txtLoggedUser->setText( this->session->getUsernameLogged().c_str() );
		this->m_ui->txtCurrentUser->setText( this->session->getUsername().c_str() );

		this->m_ui->txtCurrentKernel->setText( this->session->getCurrentLocation().getKernelName().c_str() );
		this->m_ui->txtCurrentBus->setText( this->session->getCurrentBus().c_str() );

		e_onLocationChanged();
		this->m_ui->txtInput->setFocus();
	 }
	else if ( reg_unreg == 1 ) { // unregistered
		delete this->session; this->session = NULL;
		emit close();//onSessionDestroyed();
	 }
 }

void FormConsole::session_state_changed( Session::SESSION_STATE , Session::SESSION_STATE , wosh::communication::SessionProxy*  ) {
 }

void FormConsole::session_bus_changed( const std::string& , wosh::communication::SessionProxy* ) {
	emit onBusChanged();
 }

void FormConsole::session_location_changed( const URI& , wosh::communication::SessionProxy* ) {
	emit onLocationChanged();
 }

WRESULT FormConsole::session_print_message( const std::string& message, wosh::communication::SessionProxy* ) {
 	emit onPrintMessage( QString(message.c_str()) );
	return WRET_OK;
 }

////////////////////////////////////////////////////////////////////////////////////////////// SESSION EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// SEND COMMAND

void FormConsole::shellSend() {
	if ( this->m_ui->txtInput->text().isEmpty() ) return;
	if ( this->session == NULL ) return;

	this->m_ui->txtConsole->append( QString("%1@%2# %3")
									.arg(this->session->getUsername().c_str())
									.arg(this->session->getCurrentLocation().toString().c_str())
									.arg(this->m_ui->txtInput->text()) );
	QTextCursor cursor(this->m_ui->txtConsole->textCursor());
	cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
	// no need to change thread:
	this->session->parseInput( this->m_ui->txtInput->text().toLatin1().data() );
	this->m_ui->txtInput->clear();
 }

//////////////////////////////////////////////////////////////////////////////////////////////// SEND COMMAND
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// SIGNAL->EVENTS

void FormConsole::e_onPrintMessage( const QString& message ) {
	this->m_ui->txtConsole->append( message );
 	QTextCursor cursor(this->m_ui->txtConsole->textCursor());
	cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
 }

void FormConsole::e_onBusChanged() {
	if ( this->session == NULL ) return;
	this->m_ui->txtCurrentBus->setText( this->session->getCurrentBus().c_str() );

 }
void FormConsole::e_onLocationChanged() {
	if ( this->session == NULL ) return;
	this->m_ui->lblCurrentURI->setText( QString("%1@%2#")
									.arg(this->session->getUsername().c_str())
									.arg(this->session->getCurrentLocation().toString().c_str()) );

	this->m_ui->txtCurrentKernel->setText( this->session->getCurrentLocation().getKernelName().c_str() );

	this->m_ui->txtLoggedUser->setText( this->session->getUsernameLogged().c_str() );
	this->m_ui->txtCurrentUser->setText( this->session->getUsername().c_str() );

 }

////////////////////////////////////////////////////////////////////////////////////////////// SIGNAL->EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// SESSION EVENTS
/*
void FormConsole::session_StateChanged( Session::STATE state, SessionAsynch* )
 {
	string stateStr = Session::getStateAsString(state);
	if ( state == Session::OPENED ) {
		this->m_ui->lblCurrentURI->setText( QString("%1@%2#")
											.arg(this->session->getUsername().c_str())
											.arg(this->session->getCurrentLocation().toString().c_str()) );
		if ( !this->sessionDebug ) return;
		emit s_sentMessage( QString("<font color='green'>SESSION-STATE : %1</font>").arg(stateStr.c_str()) );
	 }
	else {
		if ( !this->sessionDebug ) return;
		emit s_sentMessage( QString("<font color='red'>SESSION-STATE : %1</font>").arg(stateStr.c_str()) );
	 }
 }

void FormConsole::session_MessageQueued( Message* message, SessionAsynch* ) {
	if ( message == NULL ) return;
	if ( !this->sessionDebug ) return;
	emit s_sentMessage( QString("<font color='gray'>SESSION-MESSAGE/QUEUED : %1</font>").arg(message->getID()) );
 }

void FormConsole::session_MessageParsing( Message* message, SessionAsynch* ) {
	if ( message == NULL ) return;
	if ( !this->sessionDebug ) return;
	emit s_sentMessage( QString("SESSION-MESSAGE/PARSING : %1").arg(message->getID()) );
 }

void FormConsole::session_PostWelcome( const string& message, SessionAsynch* ) {
	if ( !this->sessionDebug ) return;
	emit s_sentMessage( QString("SESSION-WELCOME : %1").arg(message.c_str()) );
 }
*/
////////////////////////////////////////////////////////////////////////////////////////////// SESSION EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////// SETTINGS

void FormConsole::txtCurrentBus_editingFinished() {
	if ( this->session == NULL ) return;
	this->session->setCurrentBus( this->m_ui->txtCurrentBus->text().toLatin1().data() );
	// will cause callback update
 }

void FormConsole::txtCurrentKernel_editingFinished() {
	if ( this->session == NULL ) return;
	URI newUri = this->session->getCurrentLocation();
	newUri.setKernelName( this->m_ui->txtCurrentKernel->text().toLatin1().data() );
	this->session->setCurrentLocation(newUri);
	// will cause callback update
 }

void FormConsole::chkScrollAuto_clicked() {
	this->scrollAuto = this->m_ui->chkScrollAuto->isChecked();
 }

void FormConsole::cmbSessionDebug_activated(int index) {
	if ( index == 0 )
		this->sessionDebug = false;
	else
		this->sessionDebug = true;
 }

void FormConsole::cmbWordWrap_activated(int index) {
	if ( index == 0 )
		this->m_ui->txtConsole->setLineWrapMode(QTextEdit::NoWrap);
	else
		this->m_ui->txtConsole->setLineWrapMode(QTextEdit::WidgetWidth);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FormConsole::btnFontChange_clicked() {
	bool ok;
	QFont font = QFontDialog::getFont( &ok, this->m_ui->txtConsole->font(), this);
	if ( !ok )
		return;
	this->m_ui->txtConsole->setFont(font);
 }

void FormConsole::btnFontColorChange_clicked() {
	QColor color = QColorDialog::getColor(Qt::green, this);
	if ( !color.isValid() )
		return;
	QPalette pal = this->m_ui->txtInput->palette();
	pal.setColor(QPalette::Text, color);
	this->m_ui->txtConsole->setPalette(pal);
	this->m_ui->lblCurrentURI->setPalette(pal);
	this->m_ui->txtInput->setPalette(pal);
 }

void FormConsole::btnBackgroundChange_clicked() {
	QColor color = QColorDialog::getColor(Qt::green, this);
	if ( !color.isValid() )
		return;
	QPalette pal = this->m_ui->txtInput->palette();
	pal.setColor(QPalette::Background, color);
	pal.setColor(QPalette::Window, color);
	this->m_ui->txtConsole->setPalette(pal);
	this->m_ui->lblCurrentURI->setPalette(pal);
	this->m_ui->txtInput->setPalette(pal);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////// SETTINGS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace gui
}; // namespace wosh
